home *** CD-ROM | disk | FTP | other *** search
/ Deutsche Edition 1 / Deutsche Edition 1.iso / amok / 031-040 / amok32 / billard / billard.mod < prev    next >
Text File  |  1993-11-04  |  43KB  |  1,336 lines

  1. (*********************************************************************
  2.   :Program.    Billard
  3.   :Contents.   Billard-Simulation (Game)
  4.   :Author.     Stefan Salewski
  5.   :Copyright.  Shareware
  6.   :Language.   Modula-2
  7.   :Translator. M2Amiga AMSoft V3.3d
  8.   :History.    V1.0 16.Dec.1989
  9.   :Address.    Stolper Weg 3, D-2160 Stade
  10.   :Imports.    ILBMHandler,TurboFiles,Assembler2 (* my own *)
  11.   :Imports.    MemSystem   (* Autor: Nicolas Benezan *)
  12. *********************************************************************)
  13.  
  14. MODULE Billard;
  15.   FROM MemSystem IMPORT NoCareAllocMem;
  16.   FROM ILBMHandler IMPORT InitScreen,ReadInfo,ReadBody,ILBMInfo,
  17.        MaskPlane,DimOn,DimOff,MakeBitMap,FreeBitMap;
  18.   FROM BillardSound IMPORT ballSound0Ptr,ballSound1Ptr,
  19.                            borderSoundPtr,holeSoundPtr,Beep;
  20.   FROM Arts IMPORT Assert,TermProcedure,Requester;
  21.   FROM RandomNumber IMPORT PutSeed,RND;
  22.   FROM MathTrans IMPORT Sqrt,Fieee;
  23.   FROM SYSTEM IMPORT ADR,ADDRESS,CAST,BITSET,FFP,LONGSET;
  24.   FROM Exec IMPORT MemReqSet,MemReqs,Interrupt,AddIntServer,
  25.        RemIntServer,NodeType,WaitPort,GetMsg,ReplyMsg;
  26.   FROM ExecSupport IMPORT BeginIO,AbortIO;
  27.   FROM Dos IMPORT Delay;
  28.   FROM Hardware IMPORT IntFlags;
  29.   FROM Assembler2 IMPORT MaxInt,MinInt;
  30.   FROM Intuition IMPORT ScreenPtr,customScreen,ViewAddress,NewScreen,
  31.        OpenScreen,CloseScreen,ScreenToBack,menuDown,
  32.        MakeScreen,RethinkDisplay,ScreenFlagSet,ScreenFlags,
  33.        ScreenToFront,NewWindow,WindowPtr,IDCMPFlags,IDCMPFlagSet,
  34.        WindowFlags,WindowFlagSet,OpenWindow,CloseWindow,IntuiMessagePtr,
  35.        ModifyIDCMP,selectDown,Gadget,ActivationFlagSet,ActivationFlags,
  36.        GadgetFlags,GadgetFlagSet,boolGadget,AddGList,RemoveGList,
  37.        GadgetPtr,AddGadget,RemoveGadget,CurrentTime,SetPointer;
  38.   FROM GfxMacros IMPORT RemBob;
  39.   FROM Graphics IMPORT RastPortPtr,VSprite,VSpriteFlags,VSpriteFlagSet,
  40.        ViewModes,ViewModeSet,InitGels,AddVSprite,RemVSprite,GelsInfo,
  41.        SortGList,DrawGList,Text,jam2,SetBPen,
  42.        InitMasks,VSpritePtr,SetRGB4,AddBob,
  43.        Bob,BobFlagSet,SetRast,SetAPen,RectFill,InitBitMap,
  44.        RastPortFlags,DBufPacket,FreeRaster,BitMap,BltClear,BltBitMap,
  45.        BitMapPtr,Move,Draw,SetDrMd,DrawModes,DrawModeSet;
  46.  
  47.   CONST
  48.   (*
  49.     SaveAllRegs = INLINE(048E7H,0FFFEH); MOVEM.L D0-A6,-(A7)
  50.     SaveRegs    = INLINE(048E7H,03F3EH); MOVEM.L D2-D7/A2-A6,-(A7)
  51.     LoadAllRegs = INLINE(04CDFH,07FFFH); MOVEM.L (A7)+,D0-A6
  52.     LoadRegs    = INLINE(04CDFH,07CFCH); MOMEM.L (A7)+,D2-D7/A2-A6
  53.   *)
  54.     BitsPerByte=8;
  55.     PictureName='BillardTable';
  56.     ScreenHeight=256;
  57.     ScreenWidth=320;
  58.     ScreenDepth=5;
  59.     BallImageX=24; (* Position of the Balls in the picture *)
  60.     BallImageY=176;
  61.     BallImageYDigi=136;
  62.     BallImageDis=20;
  63.     MaxGels=16;
  64.     GadgetHeight=20;
  65.     MaxGadgets=13;
  66.     BobHeight=16;
  67.     BobWidth=2; (* Bytes *)
  68.     MaxVol=64;
  69.     Frame=22; (* The width of the wood-frame *)
  70.     MaxPixelPerSec=140.0;
  71.     IntPerSec=50.0; (* VBlank Interupts per second *)
  72.     HoleDiameter=19;
  73.     GroundC=1;(* ColorNumbers *)
  74.     HoleC=2;
  75.     FrameC=3;
  76.     InfoC=4;
  77.     TextC=5;
  78.     TextBorderC=6;
  79.     TextBGC=7;
  80.     FirstBallC=16;
  81.     LocEx=64; (* Tranformation to use the whole Integer-Range *)
  82.     TimeEx=50.0; (* Time-Transformation *)
  83.     MinX=0;
  84.     MaxX=ScreenWidth*LocEx;
  85.     MinY=0;
  86.     MaxY=(ScreenHeight-GadgetHeight)*LocEx;
  87.     BallDiameter=(BobWidth*8-1)*LocEx; (* one Pixel shadow *)
  88.     BallRadius=BallDiameter DIV 2;
  89.     DeltaEdge=4*LocEx; (* Difficulty of Play = HoleSize *)
  90.     DeltaMiddle=7*LocEx;
  91.     MaxStickLen=120;
  92.     Border=Frame*LocEx+BallRadius;
  93.     BobMemory=BobWidth*BobHeight*ScreenDepth;
  94.     LeftMost=Border;
  95.     RightMost=MaxX-Border;
  96.     MiddleX=MaxX DIV 2;
  97.     TopMost=Border;
  98.     BottomMost=MaxY-Border;
  99.     Tick=1.0/IntPerSec*TimeEx;
  100.     Power=3;
  101.     VMax=MaxPixelPerSec/TimeEx*FFP(LocEx);
  102.     Tuck=FFP(BallRadius)/VMax;
  103.     MaxTravels=1;
  104.     Xex=(ScreenWidth-2*Frame-BallDiameter DIV LocEx)*MaxTravels;
  105.     R=MaxPixelPerSec*MaxPixelPerSec/(2.0*FFP(Xex));
  106.     Friction=R/(TimeEx*TimeEx)*FFP(LocEx);
  107.     Tag=0;
  108.     CustomBM=ScreenFlagSet{customBitMap,screenBehind};
  109.     IDCMP=IDCMPFlagSet{gadgetUp,mouseButtons};
  110.  
  111.   TYPE
  112.     SpecialDates=RECORD
  113.                  id:CARDINAL;   (* identification-Number of this Sprite *)
  114.                  on:BOOLEAN;    (* True: This Ball is on the table *)
  115.                  x,y:FFP;       (* current location in FFP *)
  116.                  xi,yi:INTEGER; (* current location in Integer *)
  117.                  x0,y0:FFP;     (* start loc. from upper left corner *)
  118.                  v0x,v0y:FFP;   (* velocity for x- y-direction *)
  119.                  v:FFP;         (* velocity=SQRT(v0x*v0x + v0y*v0y)  *)
  120.                  t:FFP;         (* elapsed time *)
  121.                  tex:FFP;       (* at this time speed of the ball is zero *)
  122.                  rx,ry:FFP;
  123.                  inHole:INTEGER;(* in which hole is the ball?(0: on table) *)
  124.                  borderCols:INTEGER; (* how often hit the ball the border *)
  125.                  ballCols:BITSET; (* which other balls did this ball hit *)
  126.                END;
  127.  
  128.     ExtVSprite=RECORD
  129.                  vSprite:VSprite;
  130.                  bob:Bob;
  131.                  dBufPacket:DBufPacket;
  132.                  special:SpecialDates;
  133.                END;
  134.  
  135.     ExtVSpritePtr=POINTER TO ExtVSprite;
  136.     Plane=ARRAY[0..7] OF LONGCARD;
  137.     BobSpace=RECORD
  138.                planes:ARRAY[0..4] OF Plane;
  139.              END;
  140.     BobDatas=ARRAY[1..MaxGels] OF BobSpace;
  141.     String3=ARRAY[0..3-1] OF CHAR;
  142.  
  143.   VAR
  144.     gadget:ARRAY[1..MaxGadgets] OF Gadget;
  145.     gadgetXPos:ARRAY[1..MaxGadgets] OF RECORD
  146.                                      x1,x2:INTEGER
  147.                                    END;
  148.     controlInterrupt:Interrupt;
  149.     bitMapPtr:ARRAY[0..1] OF BitMapPtr;
  150.     bobDataPtr:POINTER TO BobDatas;
  151.     pointerPtr:POINTER TO ARRAY[0..21] OF CARDINAL;
  152.     tag:[0..1];
  153.     screenPtr:ScreenPtr;
  154.     windowPtr:WindowPtr;
  155.     bodyPos:LONGINT;
  156.     picInfo:ILBMInfo;
  157.     picName:ARRAY[0..32] OF CHAR;
  158.     vSprite1,vSprite2:VSprite;
  159.     sprite:ARRAY[1..MaxGels] OF ExtVSprite;
  160.     undoPos:ARRAY[1..MaxGels] OF RECORD
  161.                                    on:BOOLEAN;
  162.                                    x,y:FFP;
  163.                                  END;
  164.  
  165.     spritei,spritej:ExtVSpritePtr;
  166.     gelsInfo:GelsInfo;
  167.     iii,jjj:CARDINAL; (* reserved for Control *)
  168.     vol,vol1,vol2:FFP;(* sound-volume *)
  169.     square,dx,dy:LONGINT;
  170.     tDiv2:FFP;
  171.     vix,viy,vjx,vjy:FFP;
  172.     ddx,ddy:LONGINT;
  173.     dddx,dddy:FFP;
  174.     lambda:FFP;
  175.     controlOn:BOOLEAN;
  176.     noBallMoved:BOOLEAN;
  177.     ballsOnTable:INTEGER;
  178.     points:ARRAY [0..1] OF INTEGER;
  179.     undoPoints:ARRAY [0..1] OF INTEGER;
  180.     hits:INTEGER;
  181.     undoHits:INTEGER;
  182.     spriteCount:INTEGER;
  183.     maxTravels:INTEGER;
  184.     friction:FFP;
  185.     power:BOOLEAN;
  186.     digi:BOOLEAN;
  187.     pool:BOOLEAN;
  188.     player:[0..1];
  189.     undoPlayer:[0..1];
  190.     integer:INTEGER;
  191.  
  192. (***************************************************************************)
  193.  
  194.   PROCEDURE IntToStr(i:INTEGER;VAR str:String3);
  195.   BEGIN
  196.     str[0]:=CHAR(((i DIV 10) MOD 10)+INTEGER('0'));
  197.     str[1]:=CHAR((i          MOD 10)+INTEGER('0'));
  198.     str[2]:=0C;
  199.   END IntToStr;
  200.  
  201. (***************************************************************************)
  202.  
  203.   PROCEDURE ExtractBalls(source:BitMapPtr);
  204.   VAR
  205.     bm:BitMap;
  206.     j,k:INTEGER;
  207.     y:INTEGER;
  208.   BEGIN
  209.     IF digi THEN
  210.       y:=BallImageYDigi
  211.     ELSE
  212.       y:=BallImageY
  213.     END;
  214.     InitBitMap(bm,ScreenDepth,BobWidth*BitsPerByte,BobHeight);
  215.     FOR j:=1 TO MaxGels DO
  216.        FOR k:=0 TO ScreenDepth-1 DO
  217.         bm.planes[k]:=ADR(bobDataPtr^[j].planes[k]);
  218.       END;
  219.       integer:=BltBitMap(source,BallImageX+((j-1) MOD 8)*BallImageDis,
  220.                          y+((j-1) DIV 8)*BallImageDis,
  221.                          ADR(bm),0,0,BobHeight,BobHeight,0C0H,255,NIL);
  222.     END;
  223.   END ExtractBalls;
  224.  
  225. (*********-******************************************************************)
  226.  
  227.   (* This is a interrupt-procedure, so we have to prevent registers from *)
  228.   (* changes. Instead of t- we can use INLINE() or SYSTEM.SAVEREGS       *)
  229.   (* $t- This is a new 3.3-option to save and restore registers          *)
  230.   (* $S- turning off Stackcheck is necessary                             *)
  231.   (* $R-$V-$N-$F- this is only for more speed                            *)
  232.   PROCEDURE Control;
  233.   BEGIN
  234.     noBallMoved:=TRUE;
  235.     iii:=spriteCount;
  236.     spritei:=ADR(sprite);
  237.     REPEAT
  238.       IF spritei^.special.on THEN
  239.         WITH spritei^.special DO
  240.           t:=t+Tick;
  241.           IF t<=tex THEN
  242.             noBallMoved:=FALSE;
  243.             (*tDiv2:=t*0.5;*)
  244.             (* FFP: x:=x/2.0 <===> DEC(CAST(LONGINT,x)) *)
  245.             tDiv2:=CAST(FFP,CAST(LONGINT,t)-1);
  246.             x:=x0+t*(v0x-rx*tDiv2);
  247.             xi:=INTEGER(x);
  248.             y:=y0+t*(v0y-ry*tDiv2);
  249.             yi:=INTEGER(y);
  250.             (* FFP: (7 IN CAST(LONGSET,x)) <===> (x<0.0) *)
  251.             IF ((xi<=LeftMost) AND (7 IN CAST(LONGSET,v0x)))
  252.               OR ((xi>=RightMost) AND NOT (7 IN CAST(LONGSET,v0x))) THEN
  253.               IF pool AND ((yi<TopMost+DeltaEdge) OR
  254.                  (yi>BottomMost-DeltaEdge)) THEN
  255.                 IF ((xi<=LeftMost-BallRadius))
  256.                   OR ((xi>=RightMost+BallRadius)) THEN
  257.                   on:=FALSE;
  258.                   RemBob(ADR(spritei^.bob));
  259.                   DEC(ballsOnTable);
  260.                   INC(points[player],id);
  261.                   (*Beep(holeSoundPtr,64);*)
  262.                   IF holeSoundPtr#NIL THEN
  263.                     holeSoundPtr^.volume:=MaxVol;
  264.                     AbortIO(holeSoundPtr);
  265.                     BeginIO(holeSoundPtr);
  266.                   END
  267.                 END
  268.               ELSE
  269.                 x0:=x;
  270.                 y0:=y;
  271.                 v0x:=-v0x+rx*t;
  272.                 v0y:=v0y-ry*t;
  273.                 vol:=ABS(v0x)/(VMax/FFP(MaxVol));
  274.                 (*Beep(borderSoundPtr,INTEGER(vol));*)
  275.                 IF borderSoundPtr#NIL THEN
  276.                   borderSoundPtr^.volume:=INTEGER(vol);
  277.                   AbortIO(borderSoundPtr);
  278.                   BeginIO(borderSoundPtr);
  279.                 END;
  280.                 v:=Sqrt(v0x*v0x+v0y*v0y);
  281.                 tex:=v/friction;
  282.                 IF v#0.0 THEN
  283.                   rx:=v0x/tex;
  284.                   ry:=v0y/tex;
  285.                 END;
  286.                 t:=0.0;
  287.               END;
  288.             END;
  289.             IF on AND(((yi<=TopMost) AND (7 IN CAST(LONGSET,v0y)))
  290.               OR ((yi>=BottomMost) AND NOT (7 IN CAST(LONGSET,v0y)))) THEN
  291.               IF pool AND ((xi<LeftMost+DeltaEdge) OR
  292.                  (xi>RightMost-DeltaEdge) OR
  293.                  ((xi>MiddleX-DeltaMiddle) AND
  294.                   (xi<MiddleX+DeltaMiddle))) THEN
  295.                 IF (yi<=TopMost-BallRadius)
  296.                   OR (yi>=BottomMost+BallRadius) THEN
  297.                   on:=FALSE;
  298.                   RemBob(ADR(spritei^.bob));
  299.                   DEC(ballsOnTable);
  300.                   INC(points[player],id);
  301.                   (*Beep(holeSoundPtr,64);*)
  302.                   IF holeSoundPtr#NIL THEN
  303.                     holeSoundPtr^.volume:=MaxVol;
  304.                     AbortIO(holeSoundPtr);
  305.                     BeginIO(holeSoundPtr);
  306.                   END;
  307.                 END;
  308.               ELSE
  309.                 x0:=x;
  310.                 y0:=y;
  311.                 v0y:=-v0y+ry*t;
  312.                 v0x:=v0x-rx*t;
  313.                 vol:=ABS(v0y)/(VMax/FFP(MaxVol));
  314.                 (*Beep(borderSoundPtr,INTEGER(vol));*)
  315.                 IF borderSoundPtr#NIL THEN
  316.                   borderSoundPtr^.volume:=INTEGER(vol);
  317.                   AbortIO(borderSoundPtr);
  318.                   BeginIO(borderSoundPtr);
  319.                 END;
  320.                 v:=Sqrt(v0x*v0x+v0y*v0y);
  321.                 tex:=v/friction;
  322.                 IF v#0.0 THEN
  323.                   rx:=v0x/tex;
  324.                   ry:=v0y/tex;
  325.                 END;
  326.                 t:=0.0;
  327.               END;
  328.             END;
  329.           END;
  330.         END;
  331.       END;
  332.       INC(spritei,SIZE(ExtVSprite));
  333.       DEC(iii);
  334.     UNTIL iii=0;
  335.     iii:=spriteCount-1;
  336.     spritei:=ADR(sprite);
  337.     REPEAT
  338.       IF spritei^.special.on THEN
  339.         spritej:=spritei;
  340.         jjj:=iii;
  341.         REPEAT
  342.           INC(spritej,SIZE(ExtVSprite));
  343.           IF spritej^.special.on THEN
  344.             ddx:=spritei^.special.xi-spritej^.special.xi;
  345.             ddy:=spritei^.special.yi-spritej^.special.yi;
  346.             IF (ABS(ddx)<=BallDiameter) AND (ABS(ddy)<=BallDiameter) THEN
  347.               square:=ddx*ddx+ddy*ddy;
  348.               IF square<=BallDiameter*BallDiameter THEN
  349.                 WITH spritei^.special DO
  350.                   IF t<=tex THEN
  351.                     vix:=v0x-rx*t;
  352.                     viy:=v0y-ry*t;
  353.                   ELSE
  354.                     vix:=0.0;
  355.                     viy:=0.0;
  356.                   END;
  357.                 END;
  358.                 WITH spritej^.special DO
  359.                   IF t<=tex THEN
  360.                     vjx:=v0x-rx*t;
  361.                     vjy:=v0y-ry*t;
  362.                   ELSE
  363.                     vjx:=0.0;
  364.                     vjy:=0.0;
  365.                   END;
  366.                 END;
  367.                 dx:=ddx+LONGINT(Tuck*(vix-vjx));
  368.                 dy:=ddy+LONGINT(Tuck*(viy-vjy));
  369.                 IF dx*dx+dy*dy<square THEN
  370.                   WITH spritei^.special DO
  371.                     x0:=x;
  372.                     y0:=y;
  373.                     v0x:=vix;
  374.                     v0y:=viy;
  375.                   END;
  376.                   WITH spritej^.special DO
  377.                     x0:=x;
  378.                     y0:=y;
  379.                     v0x:=vjx;
  380.                     v0y:=vjy;
  381.                   END;
  382.                   dddx:=spritei^.special.x-spritej^.special.x;
  383.                   dddy:=spritei^.special.y-spritej^.special.y;
  384.                   lambda:=dddx*(spritej^.special.v0x-spritei^.special.v0x);
  385.                   lambda:=lambda+dddy*(spritej^.special.v0y-
  386.                                        spritei^.special.v0y);
  387.                   lambda:=lambda/(dddx*dddx+dddy*dddy);
  388.                   vol1:=lambda*dddx;
  389.                   spritei^.special.v0x:=spritei^.special.v0x+vol1;
  390.                   spritej^.special.v0x:=spritej^.special.v0x-vol1;
  391.                   vol2:=lambda*dddy;
  392.                   spritei^.special.v0y:=spritei^.special.v0y+vol2;
  393.                   spritej^.special.v0y:=spritej^.special.v0y-vol2;
  394.                   WITH spritei^.special DO
  395.                     v:=Sqrt(v0x*v0x+v0y*v0y);
  396.                     tex:=v/friction;
  397.                     IF v#0.0 THEN
  398.                       rx:=v0x/tex;
  399.                       ry:=v0y/tex;
  400.                     END;
  401.                     t:=0.0;
  402.                   END;
  403.                   WITH spritej^.special DO
  404.                     v:=Sqrt(v0x*v0x+v0y*v0y);
  405.                     tex:=v/friction;
  406.                     IF v#0.0 THEN
  407.                       rx:=v0x/tex;
  408.                       ry:=v0y/tex;
  409.                     END;
  410.                     t:=0.0;
  411.                   END;
  412.                   vol:=Sqrt(vol1*vol1+vol2*vol2)/(VMax/FFP(MaxVol));
  413.                   (*Beep(ballSound0Ptr,INTEGER(vol));
  414.                     Beep(ballSound1Ptr,INTEGER(vol));*)
  415.                   IF ballSound0Ptr#NIL THEN
  416.                     ballSound0Ptr^.volume:=INTEGER(vol);
  417.                     AbortIO(ballSound0Ptr);
  418.                     BeginIO(ballSound0Ptr);
  419.                   END;
  420.                   IF ballSound1Ptr#NIL THEN
  421.                     ballSound1Ptr^.volume:=INTEGER(vol);
  422.                     AbortIO(ballSound1Ptr);
  423.                     BeginIO(ballSound1Ptr);
  424.                   END;
  425.                 END;
  426.               END;
  427.             END;
  428.           END;
  429.           DEC(jjj);
  430.         UNTIL jjj=0;
  431.       END;
  432.       DEC(iii);
  433.       INC(spritei,SIZE(ExtVSprite));
  434.     UNTIL iii=0;
  435.   END Control;
  436.   (* $S= *)
  437.   (* $R=$V=$N=$F=*)
  438.   (* $t= *)
  439. (***************************************************************************)
  440.  
  441.   PROCEDURE StartControl;
  442.   BEGIN
  443.     Assert(NOT controlOn,ADR('AddIntServer a second time'));
  444.     controlOn:=TRUE;
  445.     WITH controlInterrupt DO
  446.       node.type:=interrupt;
  447.       node.pri:=-60;
  448.       node.name:=ADR('BillardInterrupt');
  449.       data:=NIL;
  450.       code:=ADR(Control);
  451.     END;
  452.     (* SETREG(0,0);  Only for V3.2 , Compiler-ERROR !!! *)
  453.     AddIntServer(LONGINT(vertb),ADR(controlInterrupt));
  454.   END StartControl;
  455.  
  456. (***************************************************************************)
  457.  
  458.   PROCEDURE EndControl;
  459.   BEGIN
  460.     Assert(controlOn,ADR('RemIntServer a second time'));
  461.     controlOn:=FALSE;
  462.     (* SETREG(0,0);  Only for V3.2 , Compiler-ERROR !!! *)
  463.     RemIntServer(LONGINT(vertb),ADR(controlInterrupt));
  464.   END EndControl;
  465.  
  466. (***************************************************************************)
  467.  
  468.   PROCEDURE CleanUp;
  469.     VAR
  470.       i:INTEGER;
  471.   BEGIN
  472.     (*IF CurrentLevel()<=startLevel THEN  only for Compiler V3.2 *)
  473.       IF controlOn THEN
  474.         EndControl
  475.       END;
  476.       FOR i:=1 TO MaxGels DO
  477.         IF sprite[i].special.on THEN
  478.           RemBob(ADR(sprite[i].bob))
  479.         END;
  480.       END;
  481.       IF windowPtr#NIL THEN
  482.         CloseWindow(windowPtr)
  483.       END;
  484.       IF screenPtr#NIL THEN
  485.         CloseScreen(screenPtr)
  486.       END;
  487.       FreeBitMap(bitMapPtr[0]);
  488.       FreeBitMap(bitMapPtr[1]);
  489.   END CleanUp;
  490.  
  491. (***************************************************************************)
  492.  
  493.   PROCEDURE InitGadgets;
  494.     VAR
  495.       i:INTEGER;
  496.   BEGIN
  497.     gadgetXPos[1].x1:=02;  gadgetXPos[1].x2:=34;
  498.     gadgetXPos[2].x1:=37;  gadgetXPos[2].x2:=61;
  499.     gadgetXPos[3].x1:=63;  gadgetXPos[3].x2:=72;
  500.     gadgetXPos[4].x1:=74;  gadgetXPos[4].x2:=83;
  501.     gadgetXPos[5].x1:=85;  gadgetXPos[5].x2:=102;
  502.     gadgetXPos[6].x1:=104; gadgetXPos[6].x2:=121;
  503.     gadgetXPos[7].x1:=123; gadgetXPos[7].x2:=150;
  504.     gadgetXPos[8].x1:=153; gadgetXPos[8].x2:=163;
  505.     gadgetXPos[9].x1:=166; gadgetXPos[9].x2:=181;
  506.     gadgetXPos[10].x1:=191;gadgetXPos[10].x2:=207;
  507.     gadgetXPos[11].x1:=210;gadgetXPos[11].x2:=243;
  508.     gadgetXPos[12].x1:=246;gadgetXPos[12].x2:=279;
  509.     gadgetXPos[13].x1:=282;gadgetXPos[13].x2:=317;
  510.     FOR i:=1 TO MaxGadgets DO
  511.       WITH gadget[i] DO
  512.         IF i<MaxGadgets THEN
  513.           nextGadget:=ADR(gadget[i+1])
  514.         ELSE
  515.           nextGadget:=NIL
  516.         END;
  517.         leftEdge:=gadgetXPos[i].x1+1;
  518.         topEdge:=ScreenHeight-GadgetHeight;
  519.         width:=gadgetXPos[i].x2-gadgetXPos[i].x1;
  520.         height:=GadgetHeight;
  521.         flags:=GadgetFlagSet{};
  522.         activation:=ActivationFlagSet{relVerify};
  523.         gadgetType:=boolGadget;
  524.         gadgetRender:=NIL;
  525.         selectRender:=NIL;
  526.         gadgetText:=NIL;
  527.         mutualExclude:=LONGSET{};
  528.         specialInfo:=NIL;
  529.         gadgetID:=i;
  530.         userData:=NIL;
  531.       END;
  532.     END;
  533.     INCL(gadget[8].activation,toggleSelect);
  534.     INCL(gadget[2].activation,toggleSelect);
  535.   END InitGadgets;
  536.  
  537. (***************************************************************************)
  538.  
  539.   PROCEDURE PlaceBall(num:CARDINAL;xx,yy,v0xx,v0yy:FFP);
  540.   BEGIN
  541.     WITH sprite[num].special DO
  542.       on:=TRUE;
  543.       borderCols:=0;
  544.       ballCols:={};
  545.       t:=0.0;
  546.       x0:=xx;
  547.       x:=xx;
  548.       y0:=yy;
  549.       y:=yy;
  550.       xi:=INTEGER(xx);
  551.       yi:=INTEGER(yy);
  552.       v0x:=v0xx;
  553.       v0y:=v0yy;
  554.       v:=Sqrt(v0xx*v0xx+v0yy*v0yy);
  555.       tex:=v/friction;
  556.       IF v#0.0 THEN
  557.         rx:=v0xx/tex;
  558.         ry:=v0yy/tex;
  559.       END;
  560.     END;
  561.   END PlaceBall;
  562.  
  563. (***************************************************************************)
  564.  
  565.   PROCEDURE FindNextBall(x,y:INTEGER):INTEGER;
  566.     VAR
  567.       i,next:INTEGER;
  568.       dx,dy,d,h:LONGINT;
  569.   BEGIN
  570.     d:=MAX(LONGINT);
  571.     next:=0;
  572.     FOR i:=1 TO spriteCount DO
  573.       IF sprite[i].special.on THEN
  574.         dx:=LONGINT(sprite[i].special.xi-x*LocEx);
  575.         dy:=LONGINT(sprite[i].special.yi-y*LocEx);
  576.         h:=dx*dx+dy*dy;
  577.         IF h<d THEN
  578.           d:=h;
  579.           next:=i
  580.         END;
  581.       END;
  582.     END;
  583.     RETURN next;
  584.   END FindNextBall;
  585.  
  586. (***************************************************************************)
  587.  
  588.   PROCEDURE SetBall(i:INTEGER);
  589.   VAR
  590.     x1,x2,y1,y2,oldX,oldY:INTEGER;
  591.     dx,dy:LONGINT;
  592.     intuiMessagePtr:IntuiMessagePtr;
  593.     class:IDCMPFlagSet;
  594.     code:CARDINAL;
  595.     maxStickLen,d:LONGINT;
  596.   BEGIN
  597.     IF power THEN
  598.       maxStickLen:=MaxStickLen DIV Power
  599.     ELSE
  600.       maxStickLen:=MaxStickLen
  601.     END;
  602.     INC(hits);
  603.     d:=maxStickLen*maxStickLen;
  604.     SetDrMd(ADR(screenPtr^.rastPort),DrawModeSet{complement});
  605.     x1:=sprite[i].special.xi DIV LocEx;
  606.     y1:=sprite[i].special.yi DIV LocEx;
  607.     oldX:=x1;
  608.     oldY:=y1;
  609.     ModifyIDCMP(windowPtr,IDCMPFlagSet{mouseMove,mouseButtons});
  610.     Move(ADR(screenPtr^.rastPort),x1,y1);
  611.     Draw(ADR(screenPtr^.rastPort),x1,y1);
  612.     REPEAT
  613.       WaitPort(windowPtr^.userPort);
  614.       intuiMessagePtr:=GetMsg(windowPtr^.userPort);
  615.       class:=intuiMessagePtr^.class;
  616.       code:=intuiMessagePtr^.code;
  617.       x2:=intuiMessagePtr^.mouseX;
  618.       y2:=intuiMessagePtr^.mouseY;
  619.       ReplyMsg(intuiMessagePtr);
  620.       dx:=x1-x2;
  621.       dy:=y1-y2;
  622.       IF (dx*dx+dy*dy)<=d THEN
  623.         Move(ADR(screenPtr^.rastPort),x1,y1);
  624.         Draw(ADR(screenPtr^.rastPort),oldX,oldY);
  625.         Move(ADR(screenPtr^.rastPort),x1,y1);
  626.         Draw(ADR(screenPtr^.rastPort),x2,y2);
  627.         oldX:=x2;
  628.         oldY:=y2;
  629.       END;
  630.     UNTIL (mouseButtons IN class) AND (code=selectDown);
  631.     Move(ADR(screenPtr^.rastPort),x1,y1);
  632.     Draw(ADR(screenPtr^.rastPort),oldX,oldY);
  633.     PlaceBall(i,sprite[i].special.x,sprite[i].special.y,
  634.               FFP(x1-oldX)/FFP(maxStickLen)*VMax,
  635.               FFP(y1-oldY)/FFP(maxStickLen)*VMax);
  636.     ModifyIDCMP(windowPtr,IDCMP);
  637.   END SetBall;
  638.  
  639. (***************************************************************************)
  640.  
  641.   PROCEDURE InitBalls;
  642.     VAR
  643.       num:CARDINAL;
  644.   BEGIN
  645.     FOR num:=1 TO MaxGels DO
  646.       WITH sprite[num].special DO
  647.         id:=num-1;
  648.         on:=FALSE;
  649.         x:=0.0;
  650.         y:=0.0;
  651.         t:=0.0;
  652.         x0:=0.0;
  653.         y0:=0.0;
  654.         xi:=0;
  655.         yi:=0;
  656.         v0x:=0.0;
  657.         v0y:=0.0;
  658.         v:=0.0;
  659.         tex:=0.0;
  660.         rx:=0.0;
  661.         ry:=0.0;
  662.         inHole:=0;
  663.         borderCols:=0;
  664.         ballCols:={};
  665.       END;
  666.       WITH sprite[num].vSprite DO
  667.         nextVSprite := NIL;
  668.         prevVSprite := NIL;
  669.         drawPath    := NIL;
  670.         clearPath   := NIL;
  671.         oldY        := 0;
  672.         oldX        := 0;
  673.         flags:=VSpriteFlagSet{overlay,saveBack};
  674.         x:=0;
  675.         y:=0;
  676.         height:=BobHeight;
  677.         width:=BobWidth DIV 2; (* width means the width in WORDS !!! *)
  678.         depth:=ScreenDepth;
  679.         meMask:={};
  680.         hitMask:={};
  681.         imageData:=ADR(bobDataPtr^[num]);
  682.         NoCareAllocMem(borderLine,BobWidth,TRUE);
  683.         NoCareAllocMem(collMask,BobWidth*BobHeight,TRUE);
  684.         sprColors:=NIL;
  685.         vsBob:=ADR(sprite[num].bob);
  686.         planePick:=255;
  687.         planeOnOff :=0;
  688.       END;
  689.       WITH sprite[num].dBufPacket DO
  690.         bufY:=0;
  691.         bufX:=0;
  692.         bufPath:=NIL;
  693.         NoCareAllocMem(bufBuffer,BobWidth*BobHeight*ScreenDepth,TRUE);
  694.       END;
  695.       WITH sprite[num].bob DO
  696.         flags:=BobFlagSet{};
  697.         NoCareAllocMem(saveBuffer,BobWidth*BobHeight*ScreenDepth,TRUE);
  698.         imageShadow:=sprite[num].vSprite.collMask;
  699.         before:=NIL;
  700.         after:=NIL;
  701.         bobVSprite:=ADR(sprite[num].vSprite);
  702.         bobComp:=NIL;
  703.         dBuffer:=ADR(sprite[num].dBufPacket);
  704.       END;
  705.       InitMasks(ADR(sprite[num]));
  706.     END;
  707.   END InitBalls;
  708.  
  709. (***************************************************************************)
  710.  
  711.   PROCEDURE InitAll;
  712.     VAR
  713.       newScreen:NewScreen;
  714.       newWindow:NewWindow;
  715.       i:INTEGER;
  716.   BEGIN
  717.     tag:=Tag;
  718.     screenPtr:=NIL;
  719.     windowPtr:=NIL;
  720.     bitMapPtr[0]:=NIL;
  721.     bitMapPtr[1]:=NIL;
  722.     bobDataPtr:=NIL;
  723.     controlOn:=FALSE;
  724.     noBallMoved:=FALSE;
  725.     FOR i:=1 TO MaxGels DO
  726.       sprite[i].special.on:=FALSE;
  727.     END;
  728.     TermProcedure(CleanUp);
  729.     NoCareAllocMem(bobDataPtr,SIZE(BobDatas),TRUE);
  730.     NoCareAllocMem(pointerPtr,SIZE(pointerPtr^),TRUE);
  731.     FOR i:=0 TO 21 DO
  732.       IF ODD(i) THEN
  733.         pointerPtr^[i]:=0
  734.       ELSE
  735.         pointerPtr^[i]:=256
  736.       END
  737.     END;
  738.     pointerPtr^[0]:=0;
  739.     pointerPtr^[10]:=7920;
  740.     pointerPtr^[20]:=0;
  741.     player:=0;
  742.     pool:=TRUE;
  743.     power:=FALSE;
  744.     digi:=FALSE;
  745.     spriteCount:=7;
  746.     maxTravels:=2;
  747.     friction:=Friction/FFP(maxTravels);
  748.     ballsOnTable:=spriteCount;
  749.     hits:=0;
  750.     undoHits:=0;
  751.     points[0]:=0;
  752.     points[1]:=0;
  753.     undoPoints[0]:=0;
  754.     undoPoints[1]:=0;
  755.     WITH gelsInfo DO
  756.       sprRsrvd:=0;
  757.       flags:=0;
  758.       gelHead:=NIL;
  759.       gelTail:=NIL;
  760.       nextLine:=NIL;
  761.       lastColor:=NIL;
  762.       collHandler:=NIL;
  763.       leftmost:=0;
  764.       rightmost:=ScreenWidth;
  765.       topmost:=0;
  766.       bottommost:=ScreenHeight;
  767.       firstBlissObj:=NIL;
  768.       lastBlissObj:=NIL;
  769.     END;
  770.     InitGels(ADR(vSprite1),ADR(vSprite2),ADR(gelsInfo));
  771.     InitGadgets;
  772.     bitMapPtr[0]:=MakeBitMap(ScreenWidth,ScreenHeight,ScreenDepth);
  773.     Assert(bitMapPtr[0]#NIL,ADR('Not enough Chip-Memory for BitMaps'));
  774.     bitMapPtr[1]:=MakeBitMap(ScreenWidth,ScreenHeight,ScreenDepth);
  775.     Assert(bitMapPtr[1]#NIL,ADR('Not enough Chip-Memory for BitMaps'));
  776.     picName:=PictureName;
  777.     Assert(ReadInfo(picName,picInfo,bodyPos),ADR('Picture not found'));
  778.     InitScreen(newScreen,picInfo,FALSE);
  779.     newScreen.type:=customScreen+CustomBM;
  780.     newScreen.customBitMap:=bitMapPtr[Tag];
  781.     screenPtr:=OpenScreen(newScreen);
  782.     Assert(screenPtr#NIL,ADR("Can't open Screen"));
  783.     WITH newWindow DO
  784.       leftEdge:=0;
  785.       topEdge:=0;
  786.       width:=newScreen.width;
  787.       height:=newScreen.height;
  788.       detailPen:=1;
  789.       blockPen:=0;
  790.       idcmpFlags:=IDCMP;
  791.       flags:=WindowFlagSet{simpleRefresh,borderless,reportMouse,
  792.                            rmbTrap,activate};
  793.       firstGadget:=NIL;;
  794.       checkMark:=NIL;
  795.       title:=NIL;
  796.       screen:=screenPtr;
  797.       bitMap:=NIL;
  798.       minWidth:=newScreen.width;
  799.       minHeight:=newScreen.height;
  800.       maxWidth:=newScreen.width;
  801.       maxHeight:=newScreen.height;
  802.       type:=customScreen;
  803.     END;
  804.     windowPtr:=OpenWindow(newWindow);
  805.     Assert(windowPtr#NIL,ADR("Can't open Window"));
  806.     SetPointer(windowPtr,pointerPtr,9,16,-8,-4);
  807.     DimOff(screenPtr,picInfo,0);
  808.     Assert(ReadBody(picName,bitMapPtr[0]^,bodyPos,
  809.                     picInfo.bmhd.width,
  810.                     0,0,0,0,picInfo.bmhd.width,picInfo.bmhd.height,
  811.                     MaskPlane(picInfo),(picInfo.bmhd.compression=1)),
  812.                     ADR("Can't load Picture"));
  813.     ExtractBalls(bitMapPtr[Tag]);
  814.     InitBalls;
  815.     SetAPen(ADR(screenPtr^.rastPort),0);
  816.     RectFill(ADR(screenPtr^.rastPort),Frame,BallImageYDigi,
  817.              ScreenWidth-1-Frame,ScreenHeight-1-Frame-GadgetHeight);
  818.     ScreenToFront(screenPtr);
  819.     DimOn(screenPtr,picInfo,1);
  820.     Delay(3*50);
  821.     SetAPen(ADR(screenPtr^.rastPort),GroundC);
  822.     DimOff(screenPtr,picInfo,1);
  823.     RectFill(ADR(screenPtr^.rastPort),Frame,Frame,
  824.              ScreenWidth-1-Frame,ScreenHeight-1-Frame-GadgetHeight);
  825.     integer:=BltBitMap(bitMapPtr[0],0,0,bitMapPtr[1],0,0,ScreenWidth,
  826.                  ScreenHeight,0C0H,255,NIL);
  827.     DimOn(screenPtr,picInfo,1);
  828.     (*INCL(screenPtr^.rastPort.flags,dBuffer)*);
  829.     screenPtr^.rastPort.gelsInfo:=ADR(gelsInfo);
  830.   END InitAll;
  831.  
  832. (***************************************************************************)
  833.  
  834.   PROCEDURE SetDefault(balls:INTEGER);
  835.     CONST
  836.       Sqrt3=1.732;
  837.       X=FFP(INTEGER(Sqrt3*FFP(BallDiameter)/2.0/FFP(LocEx)+1.5)*LocEx);
  838.       Y=FFP(INTEGER(FFP(BallDiameter)/2.0/FFP(LocEx)+1.5)*LocEx);
  839.     VAR
  840.       i:INTEGER;
  841.       pos:ARRAY[1..MaxGels] OF RECORD
  842.                                  x,y:FFP;
  843.                                END;
  844.   BEGIN
  845.     pos[1].x:=-5.0*X;   pos[1].y:=0.0;
  846.     pos[2].x:=0.0;      pos[2].y:=0.0;
  847.     pos[3].x:=X;        pos[3].y:=-Y;
  848.     pos[4].x:=X;        pos[4].y:=Y;
  849.     pos[5].x:=2.0*X;    pos[5].y:=-2.0*Y;
  850.     pos[6].x:=2.0*X;    pos[6].y:=0.0;
  851.     pos[7].x:=2.0*X;    pos[7].y:=2.0*Y;
  852.     pos[8].x:=3.0*X;    pos[8].y:=-3.0*Y;
  853.     pos[9].x:=3.0*X;    pos[9].y:=-Y;
  854.     pos[10].x:=3.0*X;   pos[10].y:=Y;
  855.     pos[11].x:=3.0*X;   pos[11].y:=3.0*Y;
  856.     pos[12].x:=4.0*X;   pos[12].y:=-4.0*Y;
  857.     pos[13].x:=4.0*X;   pos[13].y:=-2.0*Y;
  858.     pos[14].x:=4.0*X;   pos[14].y:=0.0;
  859.     pos[15].x:=4.0*X;   pos[15].y:=2.0*Y;
  860.     pos[16].x:=4.0*X;   pos[16].y:=4.0*Y;
  861.     FOR i:=1 TO balls DO
  862.       PlaceBall(i,FFP(MaxX DIV 2)+pos[i].x,FFP(MaxY DIV 2)+pos[i].y,0.0,0.0);
  863.     END;
  864.   END SetDefault;
  865.  
  866. (***************************************************************************)
  867.  
  868.   PROCEDURE DisplayBalls;
  869.     VAR
  870.       a:INTEGER;
  871.   BEGIN
  872.     FOR a:=1 TO spriteCount DO
  873.       sprite[a].vSprite.x:=
  874.         sprite[a].special.xi DIV LocEx-BallRadius DIV LocEx;
  875.       sprite[a].vSprite.y:=
  876.         sprite[a].special.yi DIV LocEx-BallRadius DIV LocEx;
  877.     END;
  878.     tag:=1-tag;
  879.     screenPtr^.viewPort.rasInfo^.bitMap:=bitMapPtr[tag];
  880.     screenPtr^.rastPort.bitMap:=bitMapPtr[tag];
  881.     SortGList(ADR(screenPtr^.rastPort));
  882.     DrawGList(ADR(screenPtr^.rastPort),ADR(screenPtr^.viewPort));
  883.     MakeScreen(screenPtr);
  884.     RethinkDisplay();
  885.   END DisplayBalls;
  886.  
  887. (***************************************************************************)
  888.  
  889.   PROCEDURE Undo;
  890.     VAR
  891.       i:INTEGER;
  892.   BEGIN
  893.     ballsOnTable:=0;
  894.     hits:=undoHits;
  895.     player:=undoPlayer;
  896.     points[0]:=undoPoints[0];
  897.     points[1]:=undoPoints[1];
  898.     FOR i:=1 TO MaxGels DO
  899.       IF undoPos[i].on THEN
  900.         INC(ballsOnTable);
  901.         IF NOT sprite[i].special.on THEN
  902.           AddBob(ADR(sprite[i].bob),ADR(screenPtr^.rastPort));
  903.           sprite[i].special.on:=TRUE;
  904.         END;
  905.         PlaceBall(i,undoPos[i].x,undoPos[i].y,0.0,0.0);
  906.       ELSE
  907.         IF sprite[i].special.on THEN
  908.           RemBob(ADR(sprite[i].bob));
  909.           sprite[i].special.on:=FALSE;
  910.         END;
  911.       END;
  912.     END;
  913.     DisplayBalls;
  914.     DisplayBalls;
  915.   END Undo;
  916.  
  917. (***************************************************************************)
  918.  
  919.   PROCEDURE SaveOldPosition;
  920.     VAR
  921.       i:INTEGER;
  922.   BEGIN
  923.     undoHits:=hits;
  924.     undoPoints[0]:=points[0];
  925.     undoPoints[1]:=points[1];
  926.     undoPlayer:=player;
  927.     FOR i:=1 TO MaxGels DO
  928.       undoPos[i].on:=sprite[i].special.on;
  929.       undoPos[i].x:=sprite[i].special.x;
  930.       undoPos[i].y:=sprite[i].special.y;
  931.     END;
  932.   END SaveOldPosition;
  933.  
  934. (***************************************************************************)
  935.  
  936.   PROCEDURE Info;
  937.     VAR
  938.       h,p,p0,p1,bot:String3;
  939.       i:INTEGER;
  940.   BEGIN
  941.     IntToStr(ballsOnTable,bot);
  942.     IntToStr(points[0]+points[1],p);
  943.     IntToStr(points[0],p0);
  944.     IntToStr(points[1],p1);
  945.     IntToStr(hits,h);
  946.     FOR i:=0 TO 1 DO
  947.       tag:=1-tag;
  948.       screenPtr^.viewPort.rasInfo^.bitMap:=bitMapPtr[tag];
  949.       screenPtr^.rastPort.bitMap:=bitMapPtr[tag];
  950.       SetAPen(ADR(screenPtr^.rastPort),InfoC);
  951.       SetBPen(ADR(screenPtr^.rastPort),FrameC);
  952.       SetDrMd(ADR(screenPtr^.rastPort),jam2);
  953.       Move(ADR(screenPtr^.rastPort),ScreenWidth DIV 2 +14,10);
  954.       Text(ADR(screenPtr^.rastPort),ADR(h),2);
  955.       Move(ADR(screenPtr^.rastPort),ScreenWidth DIV 2 +38,10);
  956.       Text(ADR(screenPtr^.rastPort),ADR(p0),2);
  957.       Move(ADR(screenPtr^.rastPort),ScreenWidth DIV 2 +62,10);
  958.       Text(ADR(screenPtr^.rastPort),ADR(p1),2);
  959.       Move(ADR(screenPtr^.rastPort),ScreenWidth DIV 2 +86,10);
  960.       Text(ADR(screenPtr^.rastPort),ADR(p),2);
  961.       Move(ADR(screenPtr^.rastPort),ScreenWidth DIV 2 +110,10);
  962.       Text(ADR(screenPtr^.rastPort),ADR(bot),2);
  963.     END;
  964.   END Info;
  965.  
  966. (***************************************************************************)
  967.  
  968.   PROCEDURE GetMessage;
  969.   VAR
  970.     intuiMessagePtr:IntuiMessagePtr;
  971.     gadgetPtr:GadgetPtr;
  972.     code:CARDINAL;
  973.     class:IDCMPFlagSet;
  974.     i:INTEGER;
  975.  
  976.     PROCEDURE MorePower;
  977.     BEGIN
  978.       power:=NOT power;
  979.       integer:=BltBitMap(bitMapPtr[tag]  ,0,ScreenHeight-GadgetHeight,
  980.                          bitMapPtr[1-tag],0,ScreenHeight-GadgetHeight,
  981.                          ScreenWidth,GadgetHeight,0C0H,255,NIL);
  982.     END MorePower;
  983.  
  984.     PROCEDURE BallNumbers;
  985.       VAR
  986.         picFound:BOOLEAN;
  987.     BEGIN
  988.       REPEAT
  989.         picFound:=ReadBody(picName,bitMapPtr[1-tag]^,bodyPos,
  990.                            picInfo.bmhd.width,
  991.                            BallImageX,BallImageYDigi,
  992.                            BallImageX,BallImageYDigi,
  993.                            8*BallImageDis,4*BallImageDis,
  994.                            MaskPlane(picInfo),(picInfo.bmhd.compression=1));
  995.         IF picFound THEN
  996.           digi:=NOT digi;
  997.           ExtractBalls(bitMapPtr[1-tag]);
  998.           screenPtr^.viewPort.rasInfo^.bitMap:=bitMapPtr[1-tag];
  999.           screenPtr^.rastPort.bitMap:=bitMapPtr[1-tag];
  1000.           SetAPen(ADR(screenPtr^.rastPort),GroundC);
  1001.           SetBPen(ADR(screenPtr^.rastPort),GroundC);
  1002.           SetDrMd(ADR(screenPtr^.rastPort),jam2);
  1003.           RectFill(ADR(screenPtr^.rastPort),Frame,Frame,
  1004.                    ScreenWidth-1-Frame,ScreenHeight-1-Frame-GadgetHeight);
  1005.           screenPtr^.viewPort.rasInfo^.bitMap:=bitMapPtr[tag];
  1006.           screenPtr^.rastPort.bitMap:=bitMapPtr[tag];
  1007.           DisplayBalls;
  1008.           DisplayBalls;
  1009.         END;
  1010.       UNTIL picFound OR NOT Requester(ADR('Billard:'),
  1011.             ADR("Can't find picture 'BillardTable'"),
  1012.             ADR('Try again'),ADR('Cancel'));
  1013.       ScreenToFront(screenPtr);
  1014.     END BallNumbers;
  1015.  
  1016.     PROCEDURE SetTriangle(n:INTEGER);
  1017.       VAR
  1018.         i:INTEGER;
  1019.     BEGIN
  1020.       SaveOldPosition;
  1021.       spriteCount:=n;
  1022.       ballsOnTable:=n;
  1023.       points[0]:=0;
  1024.       points[1]:=0;
  1025.       hits:=0;
  1026.       player:=0;
  1027.       FOR i:=1 TO MaxGels DO
  1028.         IF sprite[i].special.on THEN
  1029.           RemBob(ADR(sprite[i].bob));
  1030.           sprite[i].special.on:=FALSE;
  1031.         END;
  1032.       END;
  1033.       DisplayBalls;
  1034.       DisplayBalls;
  1035.       SetDefault(n);
  1036.       FOR i:=1 TO n DO
  1037.         AddBob(ADR(sprite[i].bob),ADR(screenPtr^.rastPort));
  1038.       END;
  1039.       DisplayBalls;
  1040.       DisplayBalls;
  1041.     END SetTriangle;
  1042.  
  1043.     PROCEDURE SetWithMouse;
  1044.       VAR
  1045.         intuiMessagePtr:IntuiMessagePtr;
  1046.         gadgetPtr:GadgetPtr;
  1047.         code:CARDINAL;
  1048.         class:IDCMPFlagSet;
  1049.         i,j:INTEGER;
  1050.         xx,yy:INTEGER;
  1051.         oldX,oldY:INTEGER;
  1052.         dx,dy:LONGINT;
  1053.         x,y:INTEGER;
  1054.         overlap:BOOLEAN;
  1055.         xf,yf:FFP;
  1056.     BEGIN
  1057.       SaveOldPosition;
  1058.       i:=RemoveGList(windowPtr,ADR(gadget[1]),-1);
  1059.       i:=AddGadget(windowPtr,ADR(gadget[2]),-1);
  1060.       i:=BltBitMap(bitMapPtr[tag]  ,0,ScreenHeight-GadgetHeight,
  1061.                    bitMapPtr[1-tag],0,ScreenHeight-GadgetHeight,
  1062.                    ScreenWidth,GadgetHeight,0C0H,255,NIL);
  1063.  
  1064.       xf:=FFP(Frame*LocEx DIV 2);
  1065.       yf:=2.0*FFP(Border);
  1066.       i:=1;
  1067.       FOR j:=1 TO MaxGels DO
  1068.         IF i=(MaxGels DIV 2)+1 THEN
  1069.           yf:=2.0*FFP(Border);
  1070.           xf:=FFP(MaxX)-xf;
  1071.         END;
  1072.         IF NOT sprite[j].special.on THEN
  1073.           INC(i);
  1074.           PlaceBall(j,xf,yf,0.0,0.0);
  1075.           AddBob(ADR(sprite[j].bob),ADR(screenPtr^.rastPort));
  1076.           yf:=yf+FFP(BallDiameter+LocEx);
  1077.         END;
  1078.       END;
  1079.       spriteCount:=MaxGels;
  1080.       ballsOnTable:=MaxGels;
  1081.       DisplayBalls;
  1082.       DisplayBalls;
  1083.       REPEAT
  1084.         ModifyIDCMP(windowPtr,IDCMP);
  1085.         WaitPort(windowPtr^.userPort);
  1086.         intuiMessagePtr:=GetMsg(windowPtr^.userPort);
  1087.         class:=intuiMessagePtr^.class;
  1088.         code:= intuiMessagePtr^.code;
  1089.         x:=intuiMessagePtr^.mouseX;
  1090.         y:=intuiMessagePtr^.mouseY;
  1091.         ReplyMsg(intuiMessagePtr);
  1092.         IF (mouseButtons IN class) AND (code=selectDown) THEN
  1093.           i:=FindNextBall(x,y);
  1094.           IF i#0 THEN
  1095.             oldX:=sprite[i].vSprite.x;
  1096.             oldY:=sprite[i].vSprite.y;
  1097.             ModifyIDCMP(windowPtr,IDCMPFlagSet{intuiTicks,mouseButtons});
  1098.             REPEAT
  1099.               WaitPort(windowPtr^.userPort);
  1100.               intuiMessagePtr:=GetMsg(windowPtr^.userPort);
  1101.               class:=intuiMessagePtr^.class;
  1102.               code:= intuiMessagePtr^.code;
  1103.               x:=intuiMessagePtr^.mouseX;
  1104.               y:=intuiMessagePtr^.mouseY;
  1105.               ReplyMsg(intuiMessagePtr);
  1106.               j:=1;
  1107.               overlap:=FALSE;
  1108.               xx:=x*LocEx;
  1109.               yy:=y*LocEx;
  1110.               WHILE (j<=spriteCount) AND NOT overlap DO
  1111.                 IF sprite[j].special.on AND(j#i) THEN
  1112.                   dx:=xx-sprite[j].special.xi;
  1113.                   dy:=yy-sprite[j].special.yi;
  1114.                   overlap:=(dx*dx+dy*dy)<BallDiameter*BallDiameter;
  1115.                 END;
  1116.                 INC(j);
  1117.               END;
  1118.               IF NOT overlap THEN
  1119.                 oldX:=x;
  1120.                 oldY:=y;
  1121.                 sprite[i].vSprite.x:=x-(BallRadius DIV LocEx);
  1122.                 sprite[i].vSprite.y:=y-(BallRadius DIV LocEx);
  1123.                 tag:=1-tag;
  1124.                 screenPtr^.viewPort.rasInfo^.bitMap:=bitMapPtr[tag];
  1125.                 screenPtr^.rastPort.bitMap:=bitMapPtr[tag];
  1126.                 SortGList(ADR(screenPtr^.rastPort));
  1127.                 DrawGList(ADR(screenPtr^.rastPort),ADR(screenPtr^.viewPort));
  1128.                 MakeScreen(screenPtr);
  1129.                 RethinkDisplay();
  1130.               END
  1131.             UNTIL (mouseButtons IN class) AND (code=selectDown);
  1132.             PlaceBall(i,FFP(oldX*LocEx),FFP(oldY*LocEx),0.0,0.0);
  1133.             IF tag#Tag THEN
  1134.               DisplayBalls
  1135.             END;
  1136.           END;
  1137.         END;
  1138.       UNTIL gadgetUp IN class;
  1139.       i:=BltBitMap(bitMapPtr[tag]  ,0,ScreenHeight-GadgetHeight,
  1140.                    bitMapPtr[1-tag],0,ScreenHeight-GadgetHeight,
  1141.                    ScreenWidth,GadgetHeight,0C0H,255,NIL);
  1142.       i:=RemoveGadget(windowPtr,ADR(gadget[2]));
  1143.       gadget[2].nextGadget:=ADR(gadget[3]);
  1144.       i:=AddGList(windowPtr,ADR(gadget[1]),0,-1,NIL);
  1145.       ModifyIDCMP(windowPtr,IDCMP);
  1146.       FOR i:=1 TO MaxGels DO
  1147.         WITH sprite[i].special DO
  1148.           IF on THEN
  1149.             IF (xi<LeftMost) OR (xi>RightMost) OR
  1150.                (yi<TopMost)  OR (yi>BottomMost) THEN
  1151.                   on:=FALSE;
  1152.                   RemBob(ADR(sprite[i].bob));
  1153.                   DEC(ballsOnTable);
  1154.             ELSE
  1155.               spriteCount:=i;
  1156.             END;
  1157.           END;
  1158.         END
  1159.       END;
  1160.       DisplayBalls;
  1161.       DisplayBalls;
  1162.     END SetWithMouse;
  1163.  
  1164.     PROCEDURE SetRND;
  1165.       VAR
  1166.         i,j:INTEGER;
  1167.         x,y:INTEGER;
  1168.         dx,dy:LONGINT;
  1169.         overlap:BOOLEAN;
  1170.         micros,secs:LONGINT;
  1171.     BEGIN
  1172.       SaveOldPosition;
  1173.       CurrentTime(ADR(secs),ADR(micros));
  1174.       PutSeed(ABS(secs+micros));
  1175.       FOR i:=1 TO MaxGels DO
  1176.         IF sprite[i].special.on THEN
  1177.           RemBob(ADR(sprite[i].bob));
  1178.           sprite[i].special.on:=FALSE;
  1179.         END;
  1180.       END;
  1181.       DisplayBalls;
  1182.       DisplayBalls;
  1183.       i:=1;
  1184.       WHILE i<=ballsOnTable DO
  1185.         REPEAT
  1186.           x:=RND(RightMost-LeftMost)+LeftMost;
  1187.           y:=RND(BottomMost-TopMost)+TopMost;
  1188.           overlap:=FALSE;
  1189.           j:=1;
  1190.           WHILE NOT overlap AND (j<i) DO
  1191.             dx:=x-sprite[j].special.xi;
  1192.             dy:=y-sprite[j].special.yi;
  1193.             overlap:=(dx*dx+dy*dy)<BallDiameter*BallDiameter;
  1194.             INC(j);
  1195.           END;
  1196.         UNTIL NOT overlap;
  1197.         PlaceBall(i,FFP(x),FFP(y),0.0,0.0);
  1198.         AddBob(ADR(sprite[i].bob),ADR(screenPtr^.rastPort));
  1199.         Beep(borderSoundPtr,MaxVol);
  1200.         DisplayBalls;
  1201.         DisplayBalls;
  1202.         Delay(10);
  1203.         INC(i);
  1204.       END;
  1205.     END SetRND;
  1206.  
  1207.     PROCEDURE SetFriction(more:BOOLEAN);
  1208.       VAR
  1209.         c:CHAR;
  1210.         i:INTEGER;
  1211.     BEGIN
  1212.       IF more THEN
  1213.         INC(maxTravels);
  1214.       ELSE
  1215.         DEC(maxTravels)
  1216.       END;
  1217.       maxTravels:=MaxInt(1,maxTravels);
  1218.       maxTravels:=MinInt(9,maxTravels);
  1219.       friction:=Friction/FFP(maxTravels);
  1220.       c:=CHAR(maxTravels+INTEGER('0'));
  1221.       FOR i:=0 TO 1 DO
  1222.         tag:=1-tag;
  1223.         screenPtr^.viewPort.rasInfo^.bitMap:=bitMapPtr[tag];
  1224.         screenPtr^.rastPort.bitMap:=bitMapPtr[tag];
  1225.         SetAPen(ADR(screenPtr^.rastPort),TextC);
  1226.         SetBPen(ADR(screenPtr^.rastPort),TextBGC);
  1227.         SetDrMd(ADR(screenPtr^.rastPort),jam2);
  1228.         Move(ADR(screenPtr^.rastPort),gadgetXPos[9].x2+2,ScreenHeight-8);
  1229.         Text(ADR(screenPtr^.rastPort),ADR(c),1);
  1230.       END;
  1231.     END SetFriction;
  1232.  
  1233.     PROCEDURE Pool;
  1234.     BEGIN
  1235.       pool:=NOT pool;
  1236.       DimOff(screenPtr,picInfo,1);
  1237.       SetDrMd(ADR(screenPtr^.rastPort),jam2);
  1238.       IF pool THEN
  1239.         REPEAT
  1240.           pool:=ReadBody(picName,bitMapPtr[tag]^,bodyPos,
  1241.                         picInfo.bmhd.width,
  1242.                         0,0,0,0,picInfo.bmhd.width,ScreenHeight-GadgetHeight,
  1243.                         MaskPlane(picInfo),(picInfo.bmhd.compression=1));
  1244.         UNTIL pool OR NOT Requester(ADR('Billard:'),
  1245.             ADR("Can't find picture 'BillardTable'"),
  1246.             ADR('Try again'),ADR('Cancel'));
  1247.         ScreenToFront(screenPtr);
  1248.       ELSE
  1249.         SetAPen(ADR(screenPtr^.rastPort),FrameC);
  1250.         SetBPen(ADR(screenPtr^.rastPort),FrameC);
  1251.         RectFill(ADR(screenPtr^.rastPort),0,0,
  1252.                  ScreenWidth-1,Frame-1);
  1253.         RectFill(ADR(screenPtr^.rastPort),0,0,
  1254.                  Frame-1,ScreenHeight-1-GadgetHeight);
  1255.         RectFill(ADR(screenPtr^.rastPort),0,ScreenHeight-1-GadgetHeight-Frame,
  1256.                  ScreenWidth-1,ScreenHeight-1-GadgetHeight);
  1257.         RectFill(ADR(screenPtr^.rastPort),ScreenWidth-1-Frame,0,
  1258.                  ScreenWidth-1,ScreenHeight-1-GadgetHeight);
  1259.       END;
  1260.       SetAPen(ADR(screenPtr^.rastPort),GroundC);
  1261.       SetBPen(ADR(screenPtr^.rastPort),GroundC);
  1262.       RectFill(ADR(screenPtr^.rastPort),Frame,Frame,
  1263.                ScreenWidth-1-Frame,ScreenHeight-1-Frame-GadgetHeight);
  1264.       integer:=BltBitMap(bitMapPtr[tag],0,0,bitMapPtr[1-tag],0,0,ScreenWidth,
  1265.                          ScreenHeight-GadgetHeight,0C0H,255,NIL);
  1266.       DimOn(screenPtr,picInfo,1);
  1267.       DisplayBalls;
  1268.       DisplayBalls;
  1269.     END Pool;
  1270.  
  1271.   BEGIN
  1272.     SetTriangle(spriteCount);
  1273.     SetFriction(TRUE);
  1274.     SaveOldPosition;
  1275.     integer:=AddGList(windowPtr,ADR(gadget[1]),0,-1,NIL);
  1276.     LOOP
  1277.       Info;
  1278.       WaitPort(windowPtr^.userPort);
  1279.       intuiMessagePtr:=GetMsg(windowPtr^.userPort);
  1280.       class:=intuiMessagePtr^.class;
  1281.       code:= intuiMessagePtr^.code;
  1282.       IF (mouseButtons IN class) AND (code=selectDown) THEN
  1283.         i:=FindNextBall(intuiMessagePtr^.mouseX,intuiMessagePtr^.mouseY);
  1284.         ReplyMsg(intuiMessagePtr);
  1285.         IF i#0 THEN
  1286.           integer:=RemoveGList(windowPtr,ADR(gadget[1]),-1);
  1287.           SaveOldPosition;
  1288.           SetBall(i);
  1289.           ModifyIDCMP(windowPtr,IDCMPFlagSet{});
  1290.           StartControl;
  1291.           REPEAT
  1292.             DisplayBalls;
  1293.           UNTIL noBallMoved AND (tag=Tag);
  1294.           EndControl;
  1295.           DisplayBalls;
  1296.           DisplayBalls;
  1297.           ModifyIDCMP(windowPtr,IDCMP);
  1298.           integer:=AddGList(windowPtr,ADR(gadget[1]),0,-1,NIL);
  1299.           player:=1-player;
  1300.         END;
  1301.       ELSIF (mouseButtons IN class) AND (code=menuDown) THEN
  1302.         ScreenToBack(screenPtr)
  1303.       ELSIF gadgetUp IN class THEN
  1304.         gadgetPtr:=intuiMessagePtr^.iAddress;
  1305.         i:=gadgetPtr^.gadgetID;
  1306.         ReplyMsg(intuiMessagePtr);
  1307.         CASE i OF
  1308.           |1:EXIT;
  1309.           |2:SetWithMouse;
  1310.           |3:SetTriangle(0);
  1311.           |4:SetTriangle(7);
  1312.           |5:SetTriangle(11);
  1313.           |6:SetTriangle(16);
  1314.           |7:SetRND;
  1315.           |8:MorePower;
  1316.           |9:SetFriction(FALSE);
  1317.           |10:SetFriction(TRUE);
  1318.           |11:BallNumbers;
  1319.           |12:Pool;
  1320.           |13:Undo;
  1321.         ELSE
  1322.         END;
  1323.       END;
  1324.     END;
  1325.   END GetMessage;
  1326.  
  1327. (***************************************************************************)
  1328.  
  1329. BEGIN
  1330.   (*startLevel:=CurrentLevel();*)
  1331.   InitAll;
  1332.   GetMessage;
  1333. END Billard.
  1334.  
  1335.  
  1336.